package com.zzr.zzrbackend.service.Impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.zzr.zzrbackend.mapper.LiveGroupChatRoomMapper;
import com.zzr.zzrbackend.mapper.MessageGroupDetailMapper;
import com.zzr.zzrbackend.mapper.UnreadGroupMessageNumMapper;
import com.zzr.zzrbackend.mapper.UserMapper;
import com.zzr.zzrbackend.pojo.domain.MessageGroupDetail;
import com.zzr.zzrbackend.util.TokenUtils;
import io.jsonwebtoken.Claims;
import jakarta.annotation.Resource;
import jakarta.websocket.*;
import jakarta.websocket.server.PathParam;
import jakarta.websocket.server.ServerEndpoint;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

@Component
@Slf4j
@Service
@ServerEndpoint("/api/live-chat-group/{live-room}/{token}")
public class WebSocketServerGroupImpl {

    private static UserMapper userMapper;

    @Resource
    public void init(UserMapper userMapper) {
        WebSocketServerGroupImpl.userMapper = userMapper;
    }

    private static LiveGroupChatRoomMapper liveGroupChatRoomMapper;

    @Resource
    public void init(LiveGroupChatRoomMapper liveGroupChatRoomMapper) {
        WebSocketServerGroupImpl.liveGroupChatRoomMapper = liveGroupChatRoomMapper;
    }

    private static MessageGroupDetailMapper messageGroupDetailMapper;

    @Resource
    public void init(MessageGroupDetailMapper messageGroupDetailMapper) {
        WebSocketServerGroupImpl.messageGroupDetailMapper = messageGroupDetailMapper;
    }

    private static UnreadGroupMessageNumMapper unreadGroupMessageNumMapper;

    @Resource
    public void init(UnreadGroupMessageNumMapper unreadGroupMessageNumMapper) {
        WebSocketServerGroupImpl.unreadGroupMessageNumMapper = unreadGroupMessageNumMapper;
    }


    /**
     * 用来记录当前在线连接数
     */
    private static int onlineCount = 0;
    /**
     * concurrent包的线程安全Set，用来存放每个客户端对应的WebSocket对象。
     */
    private static ConcurrentHashMap<String, WebSocketServerGroupImpl> webSocketMap = new ConcurrentHashMap<>();
    /**
     * 与某个客户端的连接会话，需要通过它来给客户端发送数据
     */
    private Session session;
    /**
     * 用token获取userName
     */
    private String userName = "";
    /**
     * 用userName获取userId
     */
    private Integer userId;
    /**
     * 接收实时聊天的房间号
     */
    private Integer liveRoom;
    /**
     * 接受用户列表
     */
    private List<Integer> toUser;

    /**
     * 连接建立成
     * 功调用的方法
     */
    @OnOpen
    public void onOpen(Session session, @PathParam("token") String token, @PathParam("live-room") Integer liveRoom) {
        //储存变量
        this.session = session;
        Claims claimsFromJwt = TokenUtils.getClaimsFromJwt(token);
        this.userName = (String) claimsFromJwt.get("userName");
        Integer userId = (Integer) claimsFromJwt.get("id");
        this.userId = userId;
        this.liveRoom = liveRoom;
        if (!(Objects.equals(userId, liveGroupChatRoomMapper.selectChildIdByRoomId(liveRoom)) || Objects.equals(userId,
                liveGroupChatRoomMapper.selectParentIdByRoomId(liveRoom)) || Objects.equals(userId,
                liveGroupChatRoomMapper.selectVolunteerIdByRoomId(liveRoom)))) {
            sendMessage("用户未有权限进入此房间");
            return;
        }
        if (webSocketMap.containsKey(this.userName)) {
            webSocketMap.remove(this.userName);
            //加入set中
            webSocketMap.put(this.userName, this);
        } else {
            //加入set中
            webSocketMap.put(this.userName, this);
            //在线数加1
            addOnlineCount();
        }
        //加入接受用户列表
        List<Integer> toUser = new ArrayList<>();
        toUser.add(liveGroupChatRoomMapper.selectChildIdByRoomId(liveRoom));
        toUser.add(liveGroupChatRoomMapper.selectParentIdByRoomId(liveRoom));
        toUser.add(liveGroupChatRoomMapper.selectVolunteerIdByRoomId(liveRoom));
        Iterator<Integer> exist = toUser.iterator();
        while (exist.hasNext()) {
            Integer tempId = exist.next();
            if (userId.equals(tempId) || tempId == null) {
                exist.remove();
            }
        }
        this.toUser = toUser;
        log.info("房间:" + liveRoom + "用户连接:" + userId + ",当前在线人数为:" + getOnlineCount());
        sendMessage("连接成功");
    }

    /**
     * 连接关闭
     * 调用的方法
     */
    @OnClose
    public void onClose() {
        if (webSocketMap.containsKey(userName)) {
            webSocketMap.remove(userName);
            //从set中删除
            subOnlineCount();
            log.info("房间:" + liveRoom + "用户退出:" + userName + ",当前在线人数为:" + getOnlineCount());
        }
    }

    /**
     * 收到客户端消
     * 息后调用的方法
     *
     * @param message 客户端发送过来的消息
     **/
    @OnMessage
    public void onMessage(String message, Session session) {
        log.info("用户消息:" + userName + ",报文:" + message);
        //可以群发消息
        //消息保存到数据库、redis
        if (StringUtils.isNotBlank(message)) {
            try {
                //解析发送的报文
                JSONObject jsonObject = JSON.parseObject(message);
                //追加发送人(防止串改)
                jsonObject.put("fromUserId", this.userId);
                //将消息存入数据库
                MessageGroupDetail messageGroupDetail = new MessageGroupDetail();
                messageGroupDetail.setFromUser(this.userId);
                messageGroupDetail.setLiveGroupChatRoomId(this.liveRoom);
                messageGroupDetail.setMessage(jsonObject.getString("contentText"));
                Date date = new Date();
                Long sendTime = date.getTime() / 1000;
                messageGroupDetail.setTime(sendTime);
                JSONObject sendJson = new JSONObject();
                sendJson.put("fromUserId", this.userId);
                sendJson.put("message", jsonObject.getString("contentText"));
                sendJson.put("time", sendTime);
                sendJson.put("responseType", "zzrServer");
                messageGroupDetailMapper.insert(messageGroupDetail);
                //传送给对应toUserName用户的websocket
                for (Integer noRead : this.toUser) {
                    String toUserName = userMapper.selectUserNameById(noRead);
                    if (StringUtils.isNotBlank(toUserName) && webSocketMap.containsKey(toUserName)) {
                        //如果该用户在线
                        webSocketMap.get(toUserName).sendMessage(sendJson.toString());
                    } else {
                        //如果该用户不在线
                        //如果用户未读信息没有初始化
                        if (unreadGroupMessageNumMapper.selectCount(this.liveRoom, noRead) == null) {
                            //初始化
                            unreadGroupMessageNumMapper.init(this.liveRoom, noRead);
                        }
                        unreadGroupMessageNumMapper.increase(this.liveRoom, noRead);
                        log.info("请求的userId:" + noRead + "不在该服务器上");
                    }
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }


    /**
     * @param session
     * @param error
     */
    @OnError
    public void onError(Session session, Throwable error) {

        log.error("用户错误:" + this.userName + ",原因:" + error.getMessage());
        sendMessage("用户错误:" + this.userName + ",原因:" + error.getMessage());
        error.printStackTrace();
    }

    /**
     * 实现服务
     * 器主动推送
     */
    public void sendMessage(String message) {
        try {
            this.session.getBasicRemote().sendText(message);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }


    /**
     * 获得此时的
     * 在线人数
     *
     * @return
     */
    public static synchronized int getOnlineCount() {
        return onlineCount;
    }

    /**
     * 在线人
     * 数加1
     */
    public static synchronized void addOnlineCount() {
        WebSocketServerGroupImpl.onlineCount++;
    }

    /**
     * 在线人
     * 数减1
     */
    public static synchronized void subOnlineCount() {
        WebSocketServerGroupImpl.onlineCount--;
    }
}
